namespace Asmex.FileViewer
{
    using System;
    using System.Collections;
    using System.IO;

    public class MDTables
    {
        private int[] _codedTokenBits;
        private Hashtable _ctok;
        private MModule _mod;
        private Table[] _td;

        public MDTables(BinaryReader reader, MModule mod)
        {
            this._mod = mod;
            this.SetupSchema(reader);
        }

        public int CodedTokenBits(Types t)
        {
            return this._codedTokenBits[(int) t];
        }

        public int CodedTokenBits(int i)
        {
            return this._codedTokenBits[i];
        }

        public Types[] CodedTokenTypes(Types t)
        {
            return (Types[]) this._ctok[t];
        }

        public MDBlob GetBlob(int offset)
        {
            if ((offset < 0) || (offset > this._mod.BlobHeap.Length))
            {
                throw new ModException("MDTables:  blob offs out of range.");
            }
            return (MDBlob) this._mod.BlobHeap.GetByOffset(offset);
        }

        public int GetBlobIndexSize()
        {
            if ((this._mod.ModHeaders.MetaDataTableHeader.HeapOffsetSizes & 4) == 0)
            {
                return 2;
            }
            return 4;
        }

        public MDGUID GetGuid(int offset)
        {
            if (offset == 0)
            {
                return MDGUID.Empty;
            }
            if ((offset < 1) || (offset > (this._mod.GUIDHeap.Length / 0x10L)))
            {
                throw new ModException("MDTables:  GUID offs out of range.");
            }
            return (MDGUID) this._mod.GUIDHeap[offset - 1];
        }

        public int GetGuidIndexSize()
        {
            if ((this._mod.ModHeaders.MetaDataTableHeader.HeapOffsetSizes & 2) == 0)
            {
                return 2;
            }
            return 4;
        }

        public string GetString(int offset)
        {
            if ((offset < 0) || (offset > this._mod.StringHeap.Length))
            {
                throw new ModException("MDTables:  string offs out of range.");
            }
            return (string) this._mod.StringHeap.GetByOffset(offset);
        }

        public int GetStringIndexSize()
        {
            if ((this._mod.ModHeaders.MetaDataTableHeader.HeapOffsetSizes & 1) == 0)
            {
                return 2;
            }
            return 4;
        }

        public Table GetTable(Types type)
        {
            int index = (int) type;
            if (index >= this._td.Length)
            {
                throw new ModException("MDTables:  No such table");
            }
            return this._td[index];
        }

        public Table GetTable(int token)
        {
            int index = token >> 0x18;
            if (index >= this._td.Length)
            {
                throw new ModException("MDTables:  No such table");
            }
            return this._td[index];
        }

        public uint GetTableRows(Types t)
        {
            int num = (int) t;
            if ((num < 0) || (num > this._mod.ModHeaders.MetaDataTableHeader.TableLengths.Length))
            {
                throw new ModException("MDHelper:  Tried to get length of nonexistant table");
            }
            return this._mod.ModHeaders.MetaDataTableHeader.TableLengths[(int) t];
        }

        private void SetupSchema(BinaryReader reader)
        {
            this._codedTokenBits = new int[] { 
                0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 
                4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
                5
             };
            this._ctok = new Hashtable();
            this._ctok[Types.TypeDefOrRef] = new Types[] { Types.TypeDef, Types.TypeRef, Types.TypeSpec };
            this._ctok[Types.HasConstant] = new Types[] { Types.Field, Types.Param, Types.Property };
            this._ctok[Types.CustomAttributeType] = new Types[] { Types.TypeRef, Types.TypeDef, Types.Method, Types.MemberRef, Types.UserString };
            this._ctok[Types.HasSemantic] = new Types[] { Types.Event, Types.Property };
            Types[] typesArray5 = new Types[4];
            typesArray5[1] = Types.ModuleRef;
            typesArray5[2] = Types.AssemblyRef;
            typesArray5[3] = Types.TypeRef;
            this._ctok[Types.ResolutionScope] = typesArray5;
            this._ctok[Types.HasFieldMarshal] = new Types[] { Types.Field, Types.Param };
            this._ctok[Types.HasDeclSecurity] = new Types[] { Types.TypeDef, Types.Method, Types.Assembly };
            this._ctok[Types.MemberRefParent] = new Types[] { Types.TypeDef, Types.TypeRef, Types.ModuleRef, Types.Method, Types.TypeSpec };
            this._ctok[Types.MethodDefOrRef] = new Types[] { Types.Method, Types.MemberRef };
            this._ctok[Types.MemberForwarded] = new Types[] { Types.Field, Types.Method };
            this._ctok[Types.Implementation] = new Types[] { Types.File, Types.AssemblyRef, Types.ExportedType };
            Types[] typesArray12 = new Types[0x13];
            typesArray12[0] = Types.Method;
            typesArray12[1] = Types.Field;
            typesArray12[2] = Types.TypeRef;
            typesArray12[3] = Types.TypeDef;
            typesArray12[4] = Types.Param;
            typesArray12[5] = Types.InterfaceImpl;
            typesArray12[6] = Types.MemberRef;
            typesArray12[8] = Types.Permission;
            typesArray12[9] = Types.Property;
            typesArray12[10] = Types.Event;
            typesArray12[11] = Types.StandAloneSig;
            typesArray12[12] = Types.ModuleRef;
            typesArray12[13] = Types.TypeSpec;
            typesArray12[14] = Types.Assembly;
            typesArray12[15] = Types.AssemblyRef;
            typesArray12[0x10] = Types.File;
            typesArray12[0x11] = Types.ExportedType;
            typesArray12[0x12] = Types.ManifestResource;
            this._ctok[Types.HasCustomAttribute] = typesArray12;
            this._td = new Table[] { 
                new Table(Types.Module, new Types[] { Types.UInt16, Types.String, Types.Guid, Types.Guid, Types.Guid }, new string[] { "Generation", "Name", "Mvid", "EncId", "EncBaseId" }, this, reader), new Table(Types.TypeRef, new Types[] { Types.ResolutionScope, Types.String, Types.String }, new string[] { "ResolutionScope", "Name", "Namespace" }, this, reader), new Table(Types.TypeDef, new Types[] { Types.UInt32, Types.String, Types.String, Types.TypeDefOrRef, Types.Field, Types.Method }, new string[] { "Flags", "Name", "Namespace", "Extends", "FieldList", "MethodList" }, this, reader), new Table(Types.FieldPtr, new Types[] { Types.Field }, new string[] { "Field" }, this, reader), new Table(Types.Field, new Types[] { Types.UInt16, Types.String, Types.Blob }, new string[] { "Flags", "Name", "Signature" }, this, reader), new Table(Types.MethodPtr, new Types[] { Types.Method }, new string[] { "Method" }, this, reader), new Table(Types.Method, new Types[] { Types.UInt32, Types.UInt16, Types.UInt16, Types.String, Types.Blob, Types.Param }, new string[] { "RVA", "ImplFlags", "Flags", "Name", "Signature", "ParamList" }, this, reader), new Table(Types.ParamPtr, new Types[] { Types.Param }, new string[] { "Param" }, this, reader), new Table(Types.Param, new Types[] { Types.UInt16, Types.UInt16, Types.String }, new string[] { "Flags", "Sequence", "Name" }, this, reader), new Table(Types.InterfaceImpl, new Types[] { Types.TypeDef, Types.TypeDefOrRef }, new string[] { "Class", "Interface" }, this, reader), new Table(Types.MemberRef, new Types[] { Types.MemberRefParent, Types.String, Types.Blob }, new string[] { "Class", "Name", "Signature" }, this, reader), new Table(Types.Constant, new Types[] { Types.UInt16, Types.HasConstant, Types.Blob }, new string[] { "Type", "Parent", "Value" }, this, reader), new Table(Types.CustomAttribute, new Types[] { Types.HasCustomAttribute, Types.CustomAttributeType, Types.Blob }, new string[] { "Type", "Parent", "Value" }, this, reader), new Table(Types.FieldMarshal, new Types[] { Types.HasFieldMarshal, Types.Blob }, new string[] { "Parent", "Native" }, this, reader), new Table(Types.Permission, new Types[] { Types.UInt16, Types.HasDeclSecurity, Types.Blob }, new string[] { "Action", "Parent", "PermissionSet" }, this, reader), new Table(Types.ClassLayout, new Types[] { Types.UInt16, Types.UInt32, Types.TypeDef }, new string[] { "PackingSize", "ClassSize", "Parent" }, this, reader), 
                new Table(Types.FieldLayout, new Types[] { Types.UInt32, Types.Field }, new string[] { "Offset", "Field" }, this, reader), new Table(Types.StandAloneSig, new Types[] { Types.Blob }, new string[] { "Signature" }, this, reader), new Table(Types.EventMap, new Types[] { Types.TypeDef, Types.Event }, new string[] { "Parent", "EventList" }, this, reader), new Table(Types.EventPtr, new Types[] { Types.Event }, new string[] { "Event" }, this, reader), new Table(Types.Event, new Types[] { Types.UInt16, Types.String, Types.TypeDefOrRef }, new string[] { "EventFlags", "Name", "EventType" }, this, reader), new Table(Types.PropertyMap, new Types[] { Types.TypeDef, Types.Property }, new string[] { "Parent", "PropertyList" }, this, reader), new Table(Types.PropertyPtr, new Types[] { Types.Property }, new string[] { "Property" }, this, reader), new Table(Types.Property, new Types[] { Types.UInt16, Types.String, Types.Blob }, new string[] { "PropFlags", "Name", "Type" }, this, reader), new Table(Types.MethodSemantics, new Types[] { Types.UInt16, Types.Method, Types.HasSemantic }, new string[] { "Semantic", "Method", "Association" }, this, reader), new Table(Types.MethodImpl, new Types[] { Types.TypeDef, Types.MethodDefOrRef, Types.MethodDefOrRef }, new string[] { "Class", "MethodBody", "MethodDeclaration" }, this, reader), new Table(Types.ModuleRef, new Types[] { Types.String }, new string[] { "Name" }, this, reader), new Table(Types.TypeSpec, new Types[] { Types.Blob }, new string[] { "Signature" }, this, reader), new Table(Types.ImplMap, new Types[] { Types.UInt16, Types.MemberForwarded, Types.String, Types.ModuleRef }, new string[] { "MappingFlags", "MemberForwarded", "ImportName", "ImportScope" }, this, reader), new Table(Types.FieldRVA, new Types[] { Types.UInt32, Types.Field }, new string[] { "RVA", "Field" }, this, reader), new Table(Types.ENCLog, new Types[] { Types.UInt32, Types.UInt32 }, new string[] { "Token", "FuncCode" }, this, reader), new Table(Types.ENCMap, new Types[] { Types.UInt32 }, new string[] { "Token" }, this, reader), 
                new Table(Types.Assembly, new Types[] { Types.UInt32, Types.UInt16, Types.UInt16, Types.UInt16, Types.UInt16, Types.UInt32, Types.Blob, Types.String, Types.String }, new string[] { "HashAlgId", "MajorVersion", "MinorVersion", "BuildNumber", "RevisionNumber", "Flags", "PublicKey", "Name", "Locale" }, this, reader), new Table(Types.AssemblyProcessor, new Types[] { Types.UInt32 }, new string[] { "Processor" }, this, reader), new Table(Types.AssemblyOS, new Types[] { Types.UInt32, Types.UInt32, Types.UInt32 }, new string[] { "OSPlatformId", "OSMajorVersion", "OSMinorVersion" }, this, reader), new Table(Types.AssemblyRef, new Types[] { Types.UInt16, Types.UInt16, Types.UInt16, Types.UInt16, Types.UInt32, Types.Blob, Types.String, Types.String, Types.Blob }, new string[] { "MajorVersion", "MinorVersion", "BuildNumber", "RevisionNumber", "Flags", "PublicKeyOrToken", "Name", "Locale", "HashValue" }, this, reader), new Table(Types.AssemblyRefProcessor, new Types[] { Types.UInt32, Types.AssemblyRef }, new string[] { "Processor", "AssemblyRef" }, this, reader), new Table(Types.AssemblyRefOS, new Types[] { Types.UInt32, Types.UInt32, Types.UInt32, Types.AssemblyRef }, new string[] { "OSPlatformId", "OSMajorVersion", "OSMinorVersion", "AssemblyRef" }, this, reader), new Table(Types.File, new Types[] { Types.UInt32, Types.String, Types.Blob }, new string[] { "Flags", "Name", "HashValue" }, this, reader), new Table(Types.ExportedType, new Types[] { Types.UInt32, Types.UInt32, Types.String, Types.String, Types.Implementation }, new string[] { "Flags", "TypeDefId", "TypeName", "TypeNamespace", "TypeImplementation" }, this, reader), new Table(Types.ManifestResource, new Types[] { Types.UInt32, Types.UInt32, Types.String, Types.Implementation }, new string[] { "Offset", "Flags", "Name", "Implementation" }, this, reader), new Table(Types.NestedClass, new Types[] { Types.TypeDef, Types.TypeDef }, new string[] { "NestedClass", "EnclosingClass" }, this, reader), new Table(Types.TypeTyPar, new Types[] { Types.UInt16, Types.TypeDef, Types.TypeDefOrRef, Types.String }, new string[] { "Number", "Class", "Bound", "Name" }, this, reader), new Table(Types.MethodTyPar, new Types[] { Types.UInt16, Types.Method, Types.TypeDefOrRef, Types.String }, new string[] { "Number", "Method", "Bound", "Name" }, this, reader)
             };
        }

        public int SizeOfType(Types type)
        {
            if (type != Types.UInt16)
            {
                if (type == Types.UInt32)
                {
                    return 4;
                }
                if (type == Types.String)
                {
                    return this.GetStringIndexSize();
                }
                if (type == Types.Blob)
                {
                    return this.GetBlobIndexSize();
                }
                if (type == Types.Guid)
                {
                    return this.GetGuidIndexSize();
                }
                if (type < Types.TypeDefOrRef)
                {
                    if (this.GetTableRows(type) >= 0x10000)
                    {
                        return 4;
                    }
                    return 2;
                }
                Types[] typesArray = this.CodedTokenTypes(type);
                if (typesArray == null)
                {
                    throw new ModException("Table:  Sizeof invalid token type.");
                }
                uint num2 = 0;
                foreach (Types types in typesArray)
                {
                    if (types != Types.UserString)
                    {
                        uint tableRows = this.GetTableRows(types);
                        if (num2 < tableRows)
                        {
                            num2 = tableRows;
                        }
                    }
                }
                num2 = num2 << this.CodedTokenBits(typesArray.Length);
                if (num2 >= 0x10000)
                {
                    return 4;
                }
            }
            return 2;
        }

        public int ToToken(Types tableType, int index)
        {
            int num = (int) tableType;
            index++;
            if (index < 0)
            {
                return -1;
            }
            return ((num << 0x18) | index);
        }

        public Table[] Tables
        {
            get
            {
                return this._td;
            }
        }
    }
}
